unit scaling_video;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls
  //----------------------------------------------------------------------------
  ,libavformat,libavformat_avio,libavutil_error,libavutil_file,libavutil_mem
  ,libavcodec,libavutil_frame,libavutil_pixfmt,libavutil_opt,libavutil_imgutils
  ,libswscale,libavutil_parseutils,libavutil_pixdesc
  //,libavcodec_avfft,libavdevice,libavfilter,libavfilter_avcodec,
  //,libavfilter_buffersink,libavfilter_buffersrc,libavfilter_formats
  //,libavformat_url,libavutil,libavutil_audio_fifo,libavutil_avstring
  //,libavutil_bprint,libavutil_buffer,libavutil_channel_layout,libavutil_common
  //,libavutil_cpu,libavutil_dict,libavutil_eval,libavutil_fifo
  //,libavutil_log,libavutil_mathematics,libavutil_md5
  //,libavutil_rational,libavutil_timestamp,libswresample,libavutil_samplefmt,libavutil_time
  //----------------------------------------------------------------------------
  ;

type
  TForm3 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    procedure fill_yuv_image(data: array of PByte; linesize: array of Integer;
          width, height, frame_index: Integer);
  public
    { Public declarations }
  end;

var
  Form3: TForm3;

implementation

{$R *.dfm}

procedure TForm3.Button1Click(Sender: TObject);
var
  src_data, dst_data: array[0..3] of PByte;
  src_linesize, dst_linesize:array[0..3] of Integer;
  src_w, src_h, dst_w, dst_h: Integer;
  src_pix_fmt, dst_pix_fmt: TAVPixelFormat;
  dst_size:string;
  dst_filename:string;
  dst_file:THandle;
  dst_bufsize:Integer;
  sws_ctx:PSwsContext;
  i, ret :Integer;
begin
//
  try
    src_w:=320;         src_h:=240;
    src_pix_fmt:=AV_PIX_FMT_YUV420P;
    dst_pix_fmt:=AV_PIX_FMT_RGB24;
    dst_filename:='a.mpg';
    dst_size  :='1024*768';

    ret:=av_parse_video_size(@dst_w,@dst_h,PAnsiChar(AnsiString(dst_size)));
    if (ret<0) then
    begin
      ShowMessageFmt('Invalid size ''%s'', must be in the form WxH or a valid size abbreviation',
            [dst_size]);
      Exit;
    end;

    dst_file:=FileCreate(dst_filename);
    if (dst_file=INVALID_HANDLE_VALUE) then
    begin
      ShowMessageFmt('Could not open destination file %s', [dst_filename]);
      Exit;
    end;

    // create scaling context
    sws_ctx:=sws_getContext(src_w,src_h, src_pix_fmt,
                  dst_w,dst_h,dst_pix_fmt,
                  SWS_BILINEAR,nil,nil,nil);
    if (not Assigned(sws_ctx)) then
    begin
      ShowMessageFmt('Impossible to create scale context for the conversion ' +
            'fmt:%s s:%dx%d -> fmt:%s s:%dx%d',
           [av_get_pix_fmt_name(src_pix_fmt), src_w, src_h,
            av_get_pix_fmt_name(dst_pix_fmt), dst_w, dst_h]);
      ret:=AVERROR_EINVAL;
      Exit;
    end;

    // allocate source and destination image buffers
    ret:=av_image_alloc(@src_data[0],@src_linesize[0],src_w,src_h,src_pix_fmt,16);
    if (ret<0) then
    begin
      ShowMessage('Could not allocate source image');
      Exit;
    end;
    // buffer is going to be written to rawvideo file, no alignment
    ret:=av_image_alloc(@dst_data[0],@dst_linesize[0],dst_w,dst_h,dst_pix_fmt,1);
    if (ret<0) then
    begin
      ShowMessage('Could not allocate destination image');
      Exit;
    end;
    dst_bufsize:=ret;

    for i:=0 to 100-1 do
    begin
      // generate synthetic video
      fill_yuv_image(src_data,src_linesize,src_w,src_h,i);
      // convert to destination format
      sws_scale(sws_ctx,@src_data[0],@src_linesize[0],0,src_h
            ,@dst_data[0],@dst_linesize[0]);
      // write scaled image to file
      FileWrite(dst_file,dst_data[0]^,dst_bufsize);
    end;

    ShowMessageFmt('Scaling succeeded. Play the output file with the command:' + sLineBreak +
         'ffplay -f rawvideo -pix_fmt %s -video_size %dx%d %s',
         [av_get_pix_fmt_name(dst_pix_fmt), dst_w, dst_h, dst_filename]);
  finally
    FileClose(dst_file);
    av_freep(@src_data[0]);
    av_freep(@dst_data[0]);
    sws_freeContext(sws_ctx);
  end;
end;

procedure TForm3.fill_yuv_image(data: array of PByte;
  linesize: array of Integer; width, height, frame_index: Integer);
var
  x,y:Integer;
begin
  // Y
  for y:=0 to height-1 do
  begin
    for x:=0 to width-1 do
      PByte(@PAnsiChar(data[0])[y*linesize[0]+x])^ := x+y+frame_index*3;
  end;
  // Cb and Cr
  for y:=0 to height div 2 - 1 do
  begin
    for x:=0 to width div 2 - 1 do
    begin
      PByte(@PAnsiChar(data[1])[y*linesize[1]+x])^ := 128+y+frame_index*2;
      PByte(@PAnsiChar(data[2])[y*linesize[2]+x])^ := 64+x+frame_index*5;
    end;
  end;
end;

end.
